using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using SpaceShooter.Utilities;

using System.Diagnostics;


namespace SpaceShooter.Components
{
    /// <summary>
    /// Component di gestione di tutte le istanze delle armi sparate durante la partita.
    /// </summary>
    public class BulletsManagerComponent : Microsoft.Xna.Framework.GameComponent
    {
        public static StateManagement.GameState gs;
        public static PlayerComponent player;

        public BulletsManagerComponent(Game game)
            : base(game)
        {
            Game.Services.AddService(typeof(BulletsManagerComponent), this);
            gs = (StateManagement.GameState)Game.Services.GetService(typeof(StateManagement.GameState));
        }

        protected override void Dispose(bool disposing)
        {
            Game.Services.RemoveService(typeof(BulletsManagerComponent));
            base.Dispose(disposing);
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            player = (PlayerComponent)Game.Services.GetService(typeof(PlayerComponent));
            base.Initialize();
        }

        /// <summary>
        /// Aggiornamento dello stato di tutti i proiettili presenti.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            //FARE ANCHE IL CONTROLLO DELLE COLLISIONI
            if (!gs.pause)
            {
                UpdateBullets(gs.playerBullets);
                UpdateBullets(gs.enemiesBullets);
            }
            base.Update(gameTime);
        }

        /// <summary>
        /// Aggiorna tutte le istanze della classe Bullet presenti nella lista
        /// Ed elimina quelle che hanno terminato il loro compito
        /// </summary>
        public void UpdateBullets(LinkedList<Bullet> list)
        {
            Bullet[] temp = new Bullet[list.Count];
            int i = 0;

            //Aggiorna tutte le istanze della classe Smoke presenti nella lista
            foreach (Bullet x in list)
            {
                if (!gs.timeTraveling)
                {
                    x.Update();
                    if (!Utility.IsInScreenSpace(Utility.newRectangleFromCenterPosition(x.position, 30, 30)))
                        x.lifeState = LifeState.DEAD;
                }
                else
                    x.TimeTravel();

                if (x.delete)
                {
                    temp[i] = x;
                    i++;
                }
            }

            //Elimina le istanze della classe Smoke che hanno terminato il loro ciclo di vita
            for (i = 0; i < temp.Length && temp[i] != null; i++)
            {
                list.Remove(temp[i]);
            }
        }

        public void onNewBulletHandler(Vector2 position, Vector2 direction, Weapons.IWeapons weapon, bool isPlayerBullet)
        {
            if (isPlayerBullet)
                gs.playerBullets.AddFirst(new Bullet(position, direction, weapon));
            else
                gs.enemiesBullets.AddFirst(new Bullet(position, direction, weapon));
        }

        #region Bullet
        public class Bullet
        {
            private LinkedList<BulletState> states;
            public Vector2 position;
            public Vector2 direction;
            public int damage;
            public bool delete;
            public int deathCounter;
            public int speed;
            public WeaponType type;
            public LifeState lifeState;

            public LinkedList<BulletState> GetStates()
            {
                return states;
            }
            public void SetStates(BulletState[] newStates)
            {
                states = new LinkedList<BulletState>(newStates);
            }

            public Bullet() { }

            public Bullet(Vector2 position, Vector2 direction, Weapons.IWeapons weapon)
            {
                this.position = position;
                this.direction = direction;
                this.damage = weapon.GetDamage(weapon.Level);
                this.speed = weapon.GetSpeed(weapon.Level);
                this.type = weapon.Type;
                delete = false;
                deathCounter = 0;
                lifeState = LifeState.NORMAL;
                states = new LinkedList<BulletState>();
            }

            public void Update()
            {
                if (lifeState != LifeState.DEAD)
                {
                    this.position.X += this.direction.X * speed;
                    this.position.Y += this.direction.Y * speed;

                    states.AddFirst(new BulletState(new Vector2(position.X, position.Y), new Vector2(direction.X, direction.Y), lifeState));
                    if (states.Count > gs.timeTank + 1)
                    {
                        states.RemoveLast();
                    }
                }
                else
                {
                    if (states.Count > 0)
                    {
                        if (states.Count + deathCounter > gs.timeTank)
                            states.RemoveLast();
                    }
                    else
                    {
                        delete = true;
                    }
                    deathCounter++;
                }
            }

            public void TimeTravel()
            {
                if (states.Count > 0)
                {
                    if (deathCounter > 0)
                        deathCounter--;
                    else
                    {
                        BulletState st = states.First.Value;
                        position = st.position;
                        direction = st.direction;
                        lifeState = st.lifeState;
                        states.RemoveFirst();
                    }
                }
                else
                {
                    delete = true;
                }
            }
        }
        #endregion

        #region BulletState

        public class BulletState
        {
            public Vector2 position;
            public Vector2 direction;
            public LifeState lifeState;

            public BulletState() { }

            public BulletState(Vector2 Position, Vector2 Direction, LifeState LifeState)
            {
                position = Position;
                direction = Direction;
                lifeState = LifeState;
            }
        }

        #endregion
    }
}
